#include <cuda_runtime.h>
#include <opencv2/opencv.hpp>

#include "smooth.h"

#define INPUT_IMAGE "in.ppm"

int main(int argc, char **argv)
{
    float
    *h_Kernel,
    *h_Input,
    *h_Buffer,
    *h_OutputCPU,
    *h_OutputGPU;

    float
    *d_Input,
    *d_Output,
    *d_Buffer;

    cv::Mat src;
    cv::Mat image;

    src = cv::imread(INPUT_IMAGE, CV_LOAD_IMAGE_COLOR);
    src.convertTo(image, CV_32FC3, 1/255.0);

    int imageW = image.cols;
    int imageH = image.rows;

    h_Kernel    = (float *)malloc(KERNEL_LENGTH * sizeof(float));
    h_Buffer    = (float *)malloc(imageW * imageH * sizeof(float));
    h_OutputCPU = (float *)malloc(imageW * imageH * sizeof(float));
    h_OutputGPU = (float *)malloc(imageW * imageH * sizeof(float));
    srand(200);

    cv::Mat channel[3];

    // divide os canais
    cv::split(image, channel);

    // aloca os arrays na gpu
    cudaMalloc((void **)&d_Input,   imageW * imageH * sizeof(float));
    cudaMalloc((void **)&d_Output,  imageW * imageH * sizeof(float));
    cudaMalloc((void **)&d_Buffer , imageW * imageH * sizeof(float));

    cv::Mat output_channels[3];

    for(int i=0;i < 3;i++)
    {
		h_Input = (float *) channel[i].data;

		cudaMemcpy(d_Input, h_Input, imageW * imageH * sizeof(float), cudaMemcpyHostToDevice);

		call_linhas(d_Buffer, d_Input, imageW,imageH);
		call_colunas(d_Output, d_Buffer, imageW, imageH);

		cudaDeviceSynchronize();
		cudaMemcpy(h_OutputGPU, d_Output, imageW * imageH * sizeof(float), cudaMemcpyDeviceToHost);

		cv::Mat o(imageW, imageH, CV_32FC1, h_OutputGPU);
		output_channels[i] = o.clone();
    }

	cv::Mat out;

	cv::merge(output_channels, 3, out);

    out.convertTo(out, CV_8UC3, 255.0);
    cv::imwrite("out.ppm", out);

    cudaFree(d_Buffer);
    cudaFree(d_Output);
    cudaFree(d_Input);
    free(h_OutputGPU);
    free(h_OutputCPU);
    free(h_Buffer);
    free(h_Kernel);

    cudaDeviceReset();

    return 0;
}
